export function renderHtml(pattern, words,uid) {
  let searchResultsContent = "";
  var typeMap = {
    'creative': '创意生成',
    'problem': '问题解决',
    'education': '学习与教育',
    'improvement': '自我提升'
  }
  // 如果是列表
  if (words.length > 0) {
    let wordList = "";
    //for (const word of words) {
    //  wordList += `<li>${word}</li>`;
    //}
    searchResultsContent = `
        <ul id="search-result" name="search-results"> 
          ${words.map((item) => {
            // Assuming item structure: [id, type, content, creator]
            // const currentUser = localStorage.getItem('uid');
            const currentUser = uid || ''; 
            console.log(currentUser);
            const isAdmin = currentUser === 'xiangyun';
            // For regular users, check if the PersonID was created by them
            // (based on the user prefix we added to the ID)
            const postfix = currentUser.substring(0, 3).charCodeAt(0).toString().substring(0, 3)
            const isOwner = currentUser && item[0].toString().endsWith(
              postfix
            );
            const canDelete = true || currentUser && (isAdmin || isOwner);
          const deleteButton = canDelete ? 
              `<button class="delete-btn" data-item-id="${item[0]}">删除</button>` : postfix;
          return `<div  data-id="result-list-${item[0]}" id="result-list"> <span class="prompt-type">` + (typeMap[item[1]] || item[1]) + '</span>' + '<span class="prompt-content">' + item[2] + `<button class="copy">复制</button> 
          ${deleteButton} </div>`
    }).join('')}
        </ul>
      `;
  }

  // 返回html
  return `<html>
    <head>
        <meta name="version" content="1.0" />
        <style>
.delete-btn {
  display: none;
}

          .prompt-type {
            min-width: 100px;
          }
          .prompt-content {
            width: 100%;
            margin-left: 20px;
            position: relative;
          }
          .prompt-content:hover {
            border: 1px solid gray;
          }
          .copy {
            position: absolute;
            display: none;
            top: -20;
            left: -10;
          }
          .prompt-content:hover button.copy {
            display: inline-block;
          }
          #result, #result-list {
              display: flex;
              justify-content: space-around;
          }
          #result {
            background-color: peachpuff;
          }
          #result-list {
            margin-top: 10px;
            background-color: beige;
          }
          #search-result {
            padding-inline-start: 0;
          }
          #perform-delete {
            display: none;
          }
          #user-container,perform-insert {
            display: flex;
            align-items: flex-end;
            flex-direction: row;
            justify-content: flex-end;
          }
          #form-header {
            display: flex;
            justify-content: space-between;
          }
          #result-list {
            display: flex;
            justify-content: flex-start;
          }
          #result {
            font-weight: bold;
            display: flex;
            justify-content: flex-start;
            column-gap: 90px;
          }
          #visualization-container {
            width: 100%;
            height: 800px;
            position: relative;
            margin: 20px 0;
          }
          #toggle-visualization {
            margin: 10px 0;
            padding: 5px 10px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
          }
        </style>
        <script src="https://cdn.bootcdn.net/ajax/libs/rxjs/7.8.1/rxjs.umd.min.js"></script> 
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    </head>
    <body>
        <div id="user-container">
          <div id="login-container">
          <label for="search-text">用户名</label>
          <input id="uid" name="uid" type="text" value="" />
          <label for="search-text">密码</label>
          <input id="auth" name="auth" type="text" value="" />
          <input type="button" id="login-button" value="登陆"></input>
          <input type="button" id="register-button" value="注册"></input>
          </div>
          <span id="user-name"></span>
          <input type="button" id="logout-button" value="注销"></input>
        </div>
        
        <div id='form-header'>
          <form id="perform-search" name="perform-search">
              <label for="search-text">Search text:</label>
              <input id="search-text" name="search-text" type="text" value="${pattern}" />
              <input type="button" id="submit-button" value="查询"></input>
          </form>
  
          <form id="perform-insert">
              <label for="search-text">类型</label>
              <select id="wechat-id" name="wechat-id" type="text" value="" >
                <option value="creative">创意生成</option>
                <option value="problem">问题解决</option>
                <option value="education">学习与教育</option>
                <option value="improvement">自我提升</option>
              </select>
              <label for="search-text">提示词</label>
              <textarea id="book-name" name="book-name" type="text" value="">
              </textarea>
              <input type="button" id="insert-button" value="增加"></input>
          </form>
        </div>
        <form id="perform-delete">
            <label for="id-text">id</label>
            <input id="id" name="id" type="text" value="" />
            <input type="button" id="delete-button" value="删除"></input>
        </form>

        <div id='result'>
          <div>类型</div>
          <div>提示词</div>
        </div>

        <button id="toggle-visualization">切换3D词云可视化</button>
        <div id="visualization-container"></div>

        <div id='result-list-container'>
          ${searchResultsContent}
        </div>
  
        <script>
        var typeMap = {
          'creative': '创意生成',
          'problem': '问题解决',
          'education': '学习与教育',
          'improvement': '自我提升'
          }
          // 查询
          document.getElementById('submit-button').addEventListener('click', (e) => {
            console.log(e)
            let inputElement = document.getElementById('search-text')
            let searchText = inputElement.value
            let resultElement = document.getElementById('result-list-container')
            console.log(searchText)
            fetch('/api/reasons?search-text=' + encodeURIComponent(searchText), {
             headers: {
              "Content-Type": "application/json",
              },
            }).then(function(response) {
              return response.json();
            }).then(function(myJson) {
              console.log(myJson.result);
              let generateHtml = function(rows) {
                return rows.map((item) => {
                  // return '<div id="result-list"><span>' + item[1]+ '</span>' + '<span>' + item[2] + '</span></div>'
                  return '<div id="result-list"><span class="prompt-type">' + (typeMap[item[1]] || item[1]) + '</span>' + '<span class="prompt-content">' + item[2] + '<button class="copy">复制</button></span></div>'
        
                }).join('')
              }
              // JSON.stringify(myJson.result.rows)
              resultElement.innerHTML = generateHtml(myJson.result.rows)
              var copyButton = document.getElementsByClassName('copy');
              Array.from(copyButton).forEach((button) => {
                button.onclick = function(e) {
                var content = e.target.parentElement.firstChild.textContent || e.target.parentElement.innerText;
                copyToClipboard(content)
                
                }
                })
            });
          })
        </script>

        
        <script>
          // 插入
          document.getElementById('insert-button').addEventListener('click', (e) => {
            console.log(e)
            let wechatElement = document.getElementById('wechat-id')
            let bookNameElement = document.getElementById('book-name')
            let wechat = wechatElement.value
            let bookName = bookNameElement.value
            let data = {
              bookName,
              wechat
            }
            let auth = localStorage.getItem('auth')
            let uid = localStorage.getItem('uid')
            fetch('/api/reasons', {
              body: JSON.stringify(data),
              method: "POST", // *GET, POST, PUT, DELETE, etc.
              headers: {
                "x-auth": auth,
                "x-uid": uid,
                "Content-Type": "application/json",
              },
            }).then(function(response) {
              return response.json();
            }).then(function(myJson) {
              location.reload();
              console.log(myJson.result);
            });
          })
        </script>

        <script>
          // 删除
          document.getElementById('delete-button').addEventListener('click', (e) => {
            let idElement = document.getElementById('id')
            let id = idElement.value
            let auth = localStorage.getItem('auth')
            let uid = localStorage.getItem('uid')
            fetch('/api/reasons/' + id , {
              method: "DELETE", // *GET, POST, PUT, DELETE, etc.
              headers: {
                "x-auth": auth,
                "x-uid": uid,
                "Content-Type": "application/json",
              },
            }).then(function(response) {
              return response.json();
            }).then(function(myJson) {
            console.log(myJson);
      // 成功删除后从DOM中移除该元素
      const id = myJson.result.query.text.match(/\\d{13}/)[0]; // Extract the ID from the response
      const itemElement = document.querySelector('[data-id="result-list-' + id + '"]');
      if (itemElement) {
        itemElement.remove();
      }
      idElement.value = ''; // Clear the input
      console.log('Item deleted successfully');
 
              console.log(myJson.result);
            });
          })
        </script>

        <script>
          // 登陆 
          document.getElementById('login-button').addEventListener('click', (e) => {
            let uidElement = document.getElementById('uid')
            let authElement = document.getElementById('auth')
            let uid = uidElement.value
            let auth = authElement.value
            fetch('/api/login', {
              method: "POST", // *GET, POST, PUT, DELETE, etc.
              headers: {
                "x-uid": uid,
                "x-auth": auth,
                "Content-Type": "application/json",
              },
            }).then(function(response) {
              return response.json();
            }).then(function(myJson) {
             if (myJson.result) { // Check if login was successful
      localStorage.setItem('auth', myJson.result.auth)
      localStorage.setItem('uid', myJson.result.uid)
      
      console.log(myJson.result);
      // Refresh page after successful login
      location.reload(); // This will refresh the page
    } else {
      // Handle login failure
      alert('Login failed');
    }

    // Add logout functionality
document.getElementById('logout-button').addEventListener('click', () => {
  localStorage.removeItem('auth');
  localStorage.removeItem('uid');
  location.reload();
});
              // localStorage.setItem('auth', myJson.result.auth)
              // localStorage.setItem('uid', myJson.result.uid)
              // console.log(myJson.result);
            });
          })
        </script>

        <script>
          // 注册 
          document.getElementById('register-button').addEventListener('click', (e) => {
            let uidElement = document.getElementById('uid')
            let authElement = document.getElementById('auth')
            let uid = uidElement.value
            let auth = authElement.value
            fetch('/api/register', {
              body: JSON.stringify( {
                uid,
                auth
              }),
              method: "POST", // *GET, POST, PUT, DELETE, etc.
              headers: {
                "x-uid": uid,
                "x-auth": auth,
                "Content-Type": "application/json",
              },
            }).then(function(response) {
              return response.json();
            }).then(function(myJson) {
              localStorage.setItem('auth', myJson.result.auth)
              localStorage.setItem('uid', myJson.result.uid)
              console.log(myJson.result);
            });
          })
        </script>
        <script>
          if(localStorage.uid && localStorage.auth) { 
            document.querySelector('#user-name').innerHTML = localStorage.uid
            document.querySelector('#login-container').style.display = 'none'
          }
        </script>
        <script>
        function copyToClipboard(text) {
  if (navigator.clipboard && window.isSecureContext) {
    // 使用 Clipboard API
    navigator.clipboard.writeText(text).then(function() {
      console.log('内容已成功复制到剪贴板');
    }).catch(function(err) {
      console.error('复制内容到剪贴板失败: ', err);
    });
  } else {
    // 回退方案
    let textArea = document.createElement("textarea");
    textArea.value = text;
    // 隐藏textarea元素
    textArea.style.position = "fixed";
    textArea.style.width = "2em";
    textArea.style.height = "2em";
    textArea.style.padding = 0;
    textArea.style.border = 'none';
    textArea.style.outline = 'none';
    textArea.style.boxShadow = 'none';
    textArea.style.background = 'transparent';
    document.body.appendChild(textArea);
    textArea.select();
    try {
      let successful = document.execCommand('copy');
      let msg = successful ? '成功复制到剪贴板' : '复制到剪贴板失败';
      console.log(msg);
    } catch (err) {
      console.error('复制内容到剪贴板失败: ', err);
    }
    document.body.removeChild(textArea);
  }
}

// 使用函数复制文本
// let contentToCopy = "这是需要复制的内容";
// copyToClipboard(contentToCopy);

var copyButton = document.getElementsByClassName('copy');
Array.from(copyButton).forEach((button) => {
  button.onclick = function(e) {
  var content = e.target.parentElement.firstChild.textContent || e.target.parentElement.innerText;
  copyToClipboard(content)
  
  }
})

        </script>

    
        <script type="text/javascript">
          document.addEventListener('DOMContentLoaded', function () {
          // 获取所有的输入框元素
          var inputs = document.querySelectorAll('#search-text');
          inputs.forEach(function(input) {
              // 给每个输入框添加keydown事件监听器
              input.addEventListener('keydown', function(event) {
                  // 检查是否按下了回车键(event.key === 'Enter' 或者 event.keyCode === 13)
                  if (event.key === 'Enter') {
                      // 阻止默认行为（即提交表单）
                      event.preventDefault();
                      // 这里可以添加其他你想要执行的操作
                  }
              });
          });
           const logoutButton = document.getElementById('logout-button');
           const loginForm = document.querySelector('#user-container');
           debugger
           const userName = document.getElementById('user-name');
      if (localStorage.getItem('uid') && localStorage.getItem('auth')) {
      // User is logged in
      userName.innerHTML = '欢迎, ' + localStorage.getItem('uid') + ' ';
      logoutButton.style.display = 'inline-block';
      loginForm.appendChild(logoutButton);
    } else {
      // User is not logged in
      logoutButton.style.display = 'none';
    }
        });
        
        // Logout functionality
        document.getElementById('logout-button').addEventListener('click', (e) => {
          e.preventDefault();
          localStorage.removeItem('auth');
          localStorage.removeItem('uid');
          location.reload();
        });
      </script>

      <script>
        // 获取Observable和相关操作符
        const { Observable, of } = rxjs;
        const { map, filter } = rxjs.operators;
        
        // 创建一个简单的Observable序列
        const source = of(1, 2, 3, 4, 5);
        
        // 使用pipe方法应用操作符
        const example = source.pipe(
          filter(num => num % 2 === 0), // 只选择偶数
          map(num => num * 2)           // 将每个数值乘以2
        );
        
        // 订阅observable来执行并接收数据
        example.subscribe(val => console.log(val));
      </script>
      <script>
        // Function to show delete buttons for authorized users
        function initializeDeleteButtons() {
          const currentUser = localStorage.getItem('uid');
          if (!currentUser) return;
          
          const deleteButtons = document.querySelectorAll('.delete-btn');
          deleteButtons.forEach(button => {
            const itemId = button.getAttribute('data-item-id');
            const isAdmin = currentUser === 'xiangyun';
                  let userPrefix = '';
              if (currentUser) {
                userPrefix = currentUser.charCodeAt(0).toString().padEnd(3, '0').substring(0, 3);
              }
              
              const isOwner = currentUser && button.dataset.itemId.toString().endsWith(userPrefix);
      
            
            if (isAdmin || isOwner) {
              button.style.display = 'inline-block';
            } else {
              button.style.display = userPrefix;
            
              }
          });
        }
        
        // Call this function after the page content is loaded
        document.addEventListener('DOMContentLoaded', function() {
          initializeDeleteButtons();
        });
    </script>
    <script>
    
    jQuery('.delete-btn').bind('click', (e) => {
            // let idElement = document.getElementById('id')
            let idElement = e.target;
            // let id = idElement.value
            let id = idElement.dataset.itemId
            let auth = localStorage.getItem('auth')
            let uid = localStorage.getItem('uid')
            fetch('/api/reasons/' + id , {
              method: "DELETE", // *GET, POST, PUT, DELETE, etc.
              headers: {
                "x-auth": auth,
                "x-uid": uid,
                "Content-Type": "application/json",
              },
            }).then(function(response) {
              return response.json();
            }).then(function(myJson) {
            console.log(myJson);
      // 成功删除后从DOM中移除该元素
      const id = myJson.result.query.text.match(/\\d{13}/)[0]; // Extract the ID from the response
      const itemElement = document.querySelector('[data-id="result-list-' + id + '"]');
      if (itemElement) {
        itemElement.remove();
      }
      idElement.value = ''; // Clear the input
      console.log('Item deleted successfully');
      // location.reload();
 
              console.log(myJson.result);
            });
      
      // alert('delete')
      })

    
    </script>
   
    <script>
      // 3D Visualization with Three.js
      let scene, camera, renderer, cloud;
      let wordsData = ${JSON.stringify(words)};
      let isVisualizationActive = false;
      
      function initVisualization() {
        const container = document.getElementById('visualization-container');
        
        // Create scene
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0xf0f0f0);
        
        // Create camera - adjusted for better perpendicular view of cards
        camera = new THREE.PerspectiveCamera(75, container.clientWidth / container.clientHeight, 0.1, 1000);
        // Increased camera distance from 35 to 50 to move it further away
        camera.position.z = 50;
        
        // Create renderer with higher resolution for clearer text
        renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(container.clientWidth, container.clientHeight);
        renderer.setPixelRatio(window.devicePixelRatio * 1.5);
        container.innerHTML = '';
        container.appendChild(renderer.domElement);
        
        // Add lights
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
        scene.add(ambientLight);
        
        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
        directionalLight.position.set(1, 1, 1);
        scene.add(directionalLight);
        
        // Create word cloud
        createWordCloud();
        
        // Add rotation animation
        function animate() {
          requestAnimationFrame(animate);
          
          if (cloud) {
            cloud.rotation.x += 0.0002;
            cloud.rotation.y += 0.001;
          }
          
          renderer.render(scene, camera);
        }
        
        animate();
        
        // Handle window resize
        window.addEventListener('resize', onWindowResize, false);
      }
      
      function onWindowResize() {
        const container = document.getElementById('visualization-container');
        camera.aspect = container.clientWidth / container.clientHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(container.clientWidth, container.clientHeight);
      }
      
      function createWordCloud() {
        if (cloud) {
          scene.remove(cloud);
        }
        
        cloud = new THREE.Group();
        scene.add(cloud);
        
        // Create text geometries
        const loader = new THREE.FontLoader();
        
        wordsData.forEach((item, index) => {
          const type = typeMap[item[1]] || item[1]; // Get type name
          const content = item[2]; // Get prompt content
            
          // Create a base for each word (type name)
          const baseGeometry = new THREE.CylinderGeometry(2, 2.5, 0.5, 32);
          const baseMaterial = new THREE.MeshPhongMaterial({ 
            color: new THREE.Color(Math.random() * 0xffffff)
          });
            
          const base = new THREE.Mesh(baseGeometry, baseMaterial);
            
            // Position bases in a spherical arrangement - increased radius from 20 to 30
            const phi = Math.acos(-1 + (2 * index) / wordsData.length);
            const theta = Math.sqrt(wordsData.length * Math.PI) * phi;
              
            base.position.set(
              30 * Math.cos(theta) * Math.sin(phi),  // Increased radius
              30 * Math.sin(theta) * Math.sin(phi),  // Increased radius
              30 * Math.cos(phi)                     // Increased radius
            );
            
            // Rotate the base to make the card face the center (camera)
            base.lookAt(0, 0, 0);
            
            // Add type label to base
            const canvas = document.createElement('canvas');
            const context = canvas.getContext('2d');
            canvas.width = 1024;
            canvas.height = 512;
            context.fillStyle = '#ffffff';
            context.font = 'Bold 48px Arial';
            context.textAlign = 'center';
            context.textBaseline = 'middle';
            context.fillText(type, 512, 256);
              
            const texture = new THREE.CanvasTexture(canvas);
            texture.minFilter = THREE.LinearFilter;
            texture.magFilter = THREE.LinearFilter;
            const textMaterial = new THREE.MeshBasicMaterial({ map: texture, side: THREE.DoubleSide });
            const textGeometry = new THREE.PlaneGeometry(6, 3);
            const textMesh = new THREE.Mesh(textGeometry, textMaterial);
              
            textMesh.position.set(0, 0, 2.5);
            textMesh.rotation.x = -0.5;
            base.add(textMesh);
              
              // Create a card for the content - increased size from 10x8 to 14x10
              const cardGeometry = new THREE.BoxGeometry(14, 10, 0.2);  // Larger card
              const cardMaterial = new THREE.MeshPhongMaterial({ 
                color: new THREE.Color(Math.random() * 0xffffff),
                transparent: true,
                opacity: 0.8
              });
                
              const card = new THREE.Mesh(cardGeometry, cardMaterial);
              card.position.set(0, 8, 0);  // Adjusted position for larger card
                  
              // Add content to card
              const contentCanvas = document.createElement('canvas');
              const contentContext = contentCanvas.getContext('2d');
              contentCanvas.width = 2048;
              contentCanvas.height = 2048;
              contentContext.fillStyle = '#000000';
              contentContext.fillRect(0, 0, contentCanvas.width, contentCanvas.height);
              contentContext.fillStyle = '#ffffff';
              contentContext.font = '48px Arial';
              contentContext.textAlign = 'center';
              contentContext.textBaseline = 'middle';
                
              // Split content into multiple lines - adjusted for larger card
              const words = content.split(' ');
              let line = '';
              let y = 120;
              const maxWidth = 1800;
              const lineHeight = 80;
              
              // Add title "Prompt Content" at the top
              contentContext.fillStyle = '#ffffff';
              contentContext.font = 'Bold 64px Arial';
              contentContext.fillText('Prompt Content', 1024, y);
              y += 120;
              contentContext.font = '48px Arial';
              
              for (let n = 0; n < words.length; n++) {
                const testLine = line + words[n] + ' ';
                const metrics = contentContext.measureText(testLine);
                if (metrics.width > maxWidth && n > 0) {
                  contentContext.fillText(line, 1024, y);
                  line = words[n] + ' ';
                  y += lineHeight;
                } else {
                  line = testLine;
                }
                
                // Limit number of lines to prevent overflow
                if (y > 1800) {
                  contentContext.fillText(line.substring(0, line.length-3) + '...', 1024, y);
                  break;
                }
              }
              
              // Draw any remaining text
              if (line && y <= 1800) {
                contentContext.fillText(line, 1024, y);
              }
                
              const contentTexture = new THREE.CanvasTexture(contentCanvas);
              contentTexture.minFilter = THREE.LinearFilter;
              contentTexture.magFilter = THREE.LinearFilter;
              const contentMaterial = new THREE.MeshBasicMaterial({ 
                map: contentTexture, 
                side: THREE.DoubleSide 
              });
              const contentGeometry = new THREE.PlaneGeometry(13.5, 9.5);  // Adjusted for larger card
              const contentMesh = new THREE.Mesh(contentGeometry, contentMaterial);
              contentMesh.position.set(0, 0, 0.11);
              // Fix mirrored text by scaling negatively on the x-axis
              contentMesh.scale.x = -1;
              card.add(contentMesh);
                
              // Add click event to copy content
              card.userData = { content: content };
                
              // Make card interactive
              card.addEventListener('mouseenter', function() {
                this.material.opacity = 1;
              });
                
              card.addEventListener('mouseleave', function() {
                this.material.opacity = 0.8;
              });
                
              base.add(card);
              cloud.add(base);
            });
          }
            
          // Make the visualization container respond to mouse events
          function setupVisualizationInteraction() {
            const container = document.getElementById('visualization-container');
            
            // Add mouse move listener for dynamic scaling
            container.addEventListener('mousemove', function(event) {
              // Calculate mouse position in normalized device coordinates
              const rect = renderer.domElement.getBoundingClientRect();
              const mouse = new THREE.Vector2();
              mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
              mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
                
              // Set up raycaster
              const raycaster = new THREE.Raycaster();
              raycaster.setFromCamera(mouse, camera);
                
              // Find intersected objects
              const intersects = raycaster.intersectObjects(cloud.children, true);
                
              // Reset scale of all cards
              cloud.children.forEach(child => {
                if (child.children[1]) { // The card is the second child
                  child.children[1].scale.set(1, 1, 1);
                }
              });
                
              // Scale up intersected card
              if (intersects.length > 0) {
                let card = intersects[0].object;
                while (card && !card.userData) {
                  card = card.parent;
                }
                
                if (card && card.userData) {
                  // Scale up when close to camera for better visibility
                  const distance = card.getWorldPosition(new THREE.Vector3()).distanceTo(camera.position);
                  // Reduced scaling factor from 100 to 50 for less pronounced zoom
                  const scale = Math.max(1, 50 / distance);
                  if (card.children[1]) { // The card is the second child
                    card.children[1].scale.set(scale, scale, scale);
                  }
                }
              }
            });
            
            container.addEventListener('click', function(event) {
              // Calculate mouse position in normalized device coordinates
              const rect = renderer.domElement.getBoundingClientRect();
              const mouse = new THREE.Vector2();
              mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
              mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
                
              // Set up raycaster
              const raycaster = new THREE.Raycaster();
              raycaster.setFromCamera(mouse, camera);
                
              // Find intersected objects
              const intersects = raycaster.intersectObjects(cloud.children, true);
                
              if (intersects.length > 0) {
                // Find the card that was clicked
                let card = intersects[0].object;
                while (card && !card.userData) {
                  card = card.parent;
                }
                  
                if (card && card.userData && card.userData.content) {
                  copyToClipboard(card.userData.content);
                  // Add visual feedback
                  const originalColor = card.material.color.getHex();
                  card.material.color.setHex(0x00ff00);
                  setTimeout(() => {
                    card.material.color.setHex(originalColor);
                  }, 200);
                }
              }
            });
          }
            
          // Add zoom handling for even clearer view when close
          function animate() {
            requestAnimationFrame(animate);
              
            if (cloud) {
              // Increased rotation speed for both X and Y axes
              cloud.rotation.x += 0.005;  // Increased from 0.0005 to 0.005 (10x faster)
              cloud.rotation.y += 0.01;   // Increased from 0.001 to 0.01 (10x faster)
            }
              
            renderer.render(scene, camera);
          }
            
          document.getElementById('toggle-visualization').addEventListener('click', function() {
            isVisualizationActive = !isVisualizationActive;
              
            if (isVisualizationActive) {
              document.getElementById('visualization-container').style.display = 'block';
              this.textContent = '隐藏3D词云可视化';
              initVisualization();
              setupVisualizationInteraction();
            } else {
              document.getElementById('visualization-container').style.display = 'none';
              this.textContent = '切换3D词云可视化';
            }
          });
            
          // Initially hide the visualization container
          document.getElementById('visualization-container').style.display = 'none';
        </script>

    </body>
  </html>
  `;
}